<?php
/**
 * A static toolkit to get and create rail objects.
 *
 * PHP versions 5
 *
 * Copyright (C)
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of ERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software
 * Fundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 *
 * @author Bastian Schröder <bs@chemanet.de>
 * @version 2007-07-19
 * @package rail
 */
class rail_factory{


	/**
	 * Create a new rail_container.
	 *
	 * @param rail_connector $pRailConnector
	 * @param rail_object $pEnvironment
	 * @param string $pName OBJ_NAME
	 * @return rail_container
	 */
	public static function create_container ( $pRailConnector, $pEnvironment, $pName = 'new_container' ) {
		return rail_factory::get_object( $pRailConnector, rail_factory::make_object( $pRailConnector, $pEnvironment, 'RAIL_CONTAINER', $pName) );
	}


	/**
	 * Create a new rail_document.
	 *
	 * @param rail_connector $pRailConnector
	 * @param rail_object $pEnvironment
	 * @param string $pName
	 * @param string $pDocument
	 * @return rail_document
	 */
	public static function create_document ( $pRailConnector, $pEnvironment, $pName = 'new_document', $pDocument = '' ) {
		$rail_document = rail_factory::get_object( $pRailConnector, rail_factory::make_object( $pRailConnector, $pEnvironment, 'RAIL_DOCUMENT', $pName) );

		if( strlen( trim($pDocument) ) > 0 )
			$rail_document->set_content( $pDocument );

		return $rail_document;
	}


	/**
	 * Create a new rail_group.
	 *
	 * @param rail_connector $pRailConnector
	 * @param rail_object $pEnvironment
	 * @param string $pName OBJ_NAME
	 * @return rail_group
	 */
	public static function create_group ( $pRailConnector, $pEnvironment, $pName = 'new_group' ) {
		$id = rail_factory::make_object( $pRailConnector, $pEnvironment, 'RAIL_GROUP', $pName);

		// set group to created group
		$pRailConnector->send_request( "UPDATE objects SET `group`='$id' WHERE id='$id' LIMIT 1" );

		return rail_factory::get_object( $pRailConnector, $id );
	}


	/**
	 * Create a new create_link.
	 *
	 * @param rail_connector $pRailConnector
	 * @param rail_object $pEnvironment
	 * @param string $pName
	 * @param rail_object $pRailObject
	 * @return rail_link
	 */
	public static function create_link ( $pRailConnector, $pEnvironment, $pName = 'new_link', $pRailObject = '' ) {
		$rail_link = rail_factory::get_object( $pRailConnector, rail_factory::make_object( $pRailConnector, $pEnvironment, 'RAIL_LINK', $pName) );

		// set link if a target isset
		if( isset( $pRailObject ) && $pRailObject instanceof rail_object )
			$rail_link->set_link( $pRailObject );

		return $rail_link;
	}


	/**
	 * Create a new rail_object.
	 *
	 * @param rail_connector $pRailConnector
	 * @param rail_object $pEnvironment
	 * @param string $pName OBJ_NAME
	 * @return rail_object
	 */
	public static function create_object ( $pRailConnector, $pEnvironment, $pName = 'new_object' ) {
		return rail_factory::get_object( $pRailConnector, rail_factory::make_object( $pRailConnector, $pEnvironment, 'RAIL_OBJECT', $pName) );
	}


	/**
	 * Create a new rail_page.
	 *
	 * @param rail_connector $pRailConnector
	 * @param rail_object $pEnvironment
	 * @param string $pName
	 * @return rail_page
	 */
	public static function create_page ( $pRailConnector, $pEnvironment, $pName = 'new_page' ) {
		$rail_page = rail_factory::get_object( $pRailConnector, rail_factory::make_object( $pRailConnector, $pEnvironment, 'RAIL_PAGE', $pName) );

		return $rail_page;
	}


	/**
	 * Create a new rail_user.
	 *
	 * @exception rail_exception
	 * @exception rail_writepermission_exception
	 * @param rail_connector $pRailConnector
	 * @param rail_object $pEnvironment
	 * @param string $pName OBJ_NAME
	 * @param string $pPasswd RAIL_PASSWD
	 * @return rail_user
	 */
	public static function create_user ( $pRailConnector, $pEnvironment, $pName = '', $pPasswd = '' ) {
		if( strlen( trim( $pName) ) == 0 )
			throw new rail_exception( null, 'Cany\'t create new user without a name!' );
		if( strlen( trim( $pPasswd) ) == 0 )
			throw new rail_exception( null, 'Can\'t create new user without a password!' );
		// check wheather the name already exist
		$data = $pRailConnector->send_request( "
			SELECT
				objects.`id`, objects_attributes.`value` as `name`
			FROM
				objects,objects_attributes
			WHERE
				objects.`id`=objects_attributes.`object` AND objects_attributes.`attribute`='OBJ_NAME' AND objects.`type`='RAIL_USER'
		" );
		while( $data_row = $data->fetch_assoc() ){
			if( $data_row['name'] != $pName )
				continue;

			throw new rail_writepermission_exception( null, "Can't create user: $pName already exist!" );
		}

		$id = rail_factory::make_object( $pRailConnector, $pEnvironment, 'RAIL_USER', $pName);

		// set user to created user
		$pRailConnector->send_request( "UPDATE objects SET `user`='$id' WHERE id='$id' LIMIT 1" );
		// set mode
		$pRailConnector->send_request( "UPDATE objects SET `mode`='110110000' WHERE id='$id' LIMIT 1" );
		// and RAIL_PASSWD attribute
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$id','RAIL_PASSWD','" . rtrim( md5( $pPasswd ) ) . "')" );

		return rail_factory::get_object( $pRailConnector, $id );
	}


	/**
	 * Get object from rail tree. requires a valid rail_id or a valid rail_path.
	 *
	 * @exception rail_exception
	 * @param rail_connector $pRailConnector
	 * @param mixed $pObject rail_id or rail_path
	 * @return rail_object
	 */
	public static function get_object ( $pRailConnector, $pObject ) {
		// locate objects rail_id if pObject is a rail_path
		if( !is_numeric($pObject) ){
			$path = trim( $pObject );
			// remove last slash, if exist
			if( substr( $path, - 1 ) == '/' )
				$path = substr( $path, 0, strlen($path) - 1 );
			// explode path to array and remove first array object (root path)
			$path = explode( '/', $path );
			unset( $path[0] );
			// return rail_root if path is a valid path to rail_root
			if( count($path) == 0 )
				return $pRailConnector->get_root();
			else{
				// for each path do
				$environment = $pRailConnector->get_root()->get_id();
				foreach( $path as $tracker ){
					$object_ids = array();
					$name = substr($tracker, 0, strrpos( $tracker, '[' )?strrpos( $tracker, '[' ):strlen($tracker) );
					// search for name in current inventory
					$data = $pRailConnector->send_request(
						"SELECT objects.id
						 FROM objects,objects_attributes
						 WHERE objects.id = objects_attributes.object AND objects.environment ='$environment' AND objects_attributes.`attribute` = 'OBJ_NAME' AND objects_attributes.`value` = '" . urldecode( $name ) . "' ORDER BY `id`"
					);
					// store all founded objects as id in an array
					$possible_objects = array();
					while( $data_row = $data->fetch_assoc() )
						$possible_objects[] = $data_row['id'];
					// get next environment
					if( count($possible_objects) <= 0 )
						throw new rail_exception( null, 'Object dosn\'t exist!' );
					$environment = $possible_objects[ (strrpos( $tracker, '[' ) ? substr( $tracker, strrpos( $tracker, '[' ) + 1, strlen( $tracker ) - strrpos( $tracker, '[' ) - 2 ) - 1 : 0) ];
				}
				// last founded environment is the requested object id
				$pObject = $environment;
			}
		}

		// get type of possible rail object
		$rail_type = $pRailConnector->send_request( "SELECT `type` FROM objects WHERE `id`='$pObject' LIMIT 1" )->fetch_assoc();
		$rail_type = $rail_type['type'];

		// throw an exception, if the rail object dosn't exist.
		if( strlen($rail_type) == 0 )
			throw new rail_exception( null, 'Object dosn\'t exist!' );
		if( !class_exists($rail_type) )
			throw new rail_exception( null, "Can't get object! type '$rail_type' not supported." );

		// return object
		return new $rail_type( $pRailConnector, $pObject );
	}


	/**
	 * Return rail_object if object exist otherwise return false.
	 *
	 * @param rail_connector
	 * @param mixed rail_id or rail_path
	 * @return mixed
	 */
	public static function is_object ( $pRailConnector, $pObject ) {
		try{
			return rail_factory::get_object( $pRailConnector, $pObject );
		}
		catch( rail_exception $e ){ return false; }
	}


	/**
	 * This method should never called careless!
	 * Insert a new rail object to database and returned new rail_id. Set all attributes and values needed for a simple
	 * rail object. But this method dosn't check whether $pRailType is a valid raul type. And all extra attributes and
	 * data has set manually if make a nontrivial rail object.
	 * A save method call is: rail_factory::make_object($rail, $object, 'RAIL_OBJECT');
	 *
	 * @exception rail_exception
	 * @param rail_connector $pRailConnector
	 * @param rail_object $pEnvironment
	 * @param string $pRailType
	 * @param string $pName
	 * @return int
	 */
	public static function make_object ( $pRailConnector, $pEnvironment, $pRailType, $pName = 'new' ) {
		$timestamp = time();

		if( !$pEnvironment instanceof rail_object )
			throw new rail_exception( $pEnvironment, 'Environment dosn\'t exist!' );
		if( !$pEnvironment->is_writeable( $pRailConnector->get_user() ) )
		 	throw new rail_writepermission_exception( $pEnvironment, 'Can\'t write to environments inventory.' );

		// Set object
		$pRailConnector->send_request( "INSERT INTO objects ( `type`, `environment`, `user`, `group`, `mode` ) VALUES ('" . strtoupper($pRailType) . "', '" . $pEnvironment->get_id() . "', '" . $pRailConnector->get_user()->get_id() . "', '" . $pRailConnector->get_user()->get_group()->get_id() . "', '110100000')" );

		$data = $pRailConnector->send_request( "SELECT `id` FROM objects WHERE `type`='" . strtoupper($pRailType) . "' AND `environment`='" . $pEnvironment->get_id() . "' ORDER BY id DESC LIMIT 1" )->fetch_assoc();
		$new_rail_id = $data["id"];

		// Set OBJ_NAME
		$name = strlen( trim( $pName ) ) > 0 ? trim( $pName ) : "new";
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','OBJ_NAME','$name')" );

		// Set OBJ_TIME_CREATE and OBJ_TIME_LASTWRITE
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','OBJ_TIME_CREATE','$timestamp')" );
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','OBJ_TIME_LASTWRITE','$timestamp')" );
		// update OBJ_TIME_LASTWRITE from environment
		$pRailConnector->send_request( "UPDATE objects_attributes SET `value`='$timestamp' WHERE `object`='" . $pEnvironment->get_id() . "' AND `attribute`='OBJ_TIME_LASTWRITE'" );

		return $new_rail_id;
	}

} // End of rail_factory
?>